package com.lance.shiro.service;

import com.lance.shiro.entity.EmailGroup;
import com.lance.shiro.entity.IAttachment;
import com.lance.shiro.entity.ISolicitor;
import com.lance.shiro.entity.IUser;
import com.lance.shiro.utils.ConvertUtils;
import com.lance.shiro.utils.UserStatus;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;


@Service
public class UMailServiceImpl implements UMailService {
    private static Logger logger = LogManager.getLogger();

    @Value("${mail.domain}")
    private String mailDomain;

    @Value("${mail.server}")
    private String mailServer;

    @Value("${mail.api}")
    private String mailApi;

    @Value("${mail.admin.username}")
    private String mailAdmin;

    @Value("${mail.admin.password}")
    private String adminPassword;

    @Value("${mail.manager.username}")
    private String mailManager;

    @Value("${mail.manager.password}")
    private String managerPassword;

    @Value("${mail.manager.nickname}")
    private String managerNick;

    @Value("${mail.defaultPassword}")
    private String defaultPassword;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private UserService userService;

    @Autowired
    private CommonService commonService;

    @Autowired
    private SolicitorService solicitorService;

    /**
     * <pre>
     * username：	域管理员的账号（非空）
     * password：	域管理员的密码，MD5加密（非空）
     * domain:		域管理员所在域名，默认值是主域
     * account：		添加该域名下的邮箱账号，如abc（非空）
     * pwd：		该邮箱账号的密码，明文（非空）
     * realname：	该邮箱账号的真实姓名，如abc（非空）
     * mbsize：		该邮箱账号的邮件空间大小，数字型，单位M，如100
     * ndsize：		该邮箱账号的网络硬盘大小，数字型，单位M，如100
     * disabled：	该邮箱账号是否被禁用，选项型，1是禁用，-1是非禁用
     * limit_send：	该邮箱发信功能是否被限制，选项型，1是限制，-1是正常
     * limit_recv:	该邮箱收信功能是否被限制，选项型，1是限制，-1是正常
     * recvsms：		该邮箱短信通知是否被限制，选项型，1是限制，-1是正常
     * limit_ip：		该邮箱的限制登录的IP（段）地址
     * eenumber：	该邮箱用户的工号
     * tel_mobile：	该邮箱用户的手机号码
     * tel_home：	该邮箱用户的住宅电话
     * tel_qq：		该邮箱用户的qq
     * tel_msn：		该邮箱用户的msn
     * tel_work：	该邮箱用户的公司电话
     *
     * adminpass： 超级管理员密码MD5，如cd2c3a3529b259d42718a6a606c63f0a（password不知道为空时非空）
     * adminname：	超级管理员用户名如：admin（password不知道为空时非空）
     *
     * </pre>
     */
    @Override
    public Map<String, String> addMailBox(String username, String realname, String password) throws Exception {
        String url = mailApi + "?do=addMailbox";

        Map<String, String> ret = new HashMap<String, String>();


        if (StringUtils.isBlank(username)) {
            ret.put("status", "-1");
            ret.put("data", "account  cant be null");
            return ret;
        }


        if (StringUtils.isBlank(realname)) {
            ret.put("status", "-1");
            ret.put("data", "realname cant be null");
            return ret;
        }
        if (StringUtils.isBlank(password)) {
            password = defaultPassword;
        }
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("account", username);
        map.add("pwd", password);
        map.add("username", mailAdmin);
        map.add("password", adminPassword);
        map.add("domain", mailDomain);
        map.add("realname", realname);
        logger.debug(url);
        logger.debug(map);
        String responseText = restTemplate.postForObject(url, map, String.class);
        logger.debug(responseText);
        ret = parseSimpleResult(responseText);
        if (ret != null && ret.containsKey("status") && ret.get("status").equals("0")) {
            return ret;
        } else {
            throw new Exception("Create email error!");
        }
    }

    /**
     * 删除
     *
     * @param username
     * @return
     */
    @Override
    public Map<String, String> delMailbox(String username) throws Exception {
        String url = mailApi + "?do=delMailbox";

        Map<String, String> ret = new HashMap<String, String>();


        if (StringUtils.isBlank(username)) {
            ret.put("status", "-1");
            ret.put("data", "account  cant be null");
            return ret;
        }

        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("account", username);
        map.add("username", mailAdmin);
        map.add("password", adminPassword);
        map.add("domain", mailDomain);
        logger.debug(url);
        logger.debug(map);
        String responseText = restTemplate.postForObject(url, map, String.class);
        logger.debug(responseText);
        ret = parseSimpleResult(responseText);
        if (ret != null && ret.containsKey("status") && ret.get("status").equals("0")) {
            return ret;
        } else {
            throw new Exception("Delete email error!");
        }
    }

    @Override
    public Map<String, String> sendManagerMail(String to, String bcc, String subject, String body) throws Exception {
        Map<String, String> ret = new HashMap<String, String>();
        if (StringUtils.isBlank(to)) {
            ret.put("status", "-1");
            ret.put("data", "receiver cant be empty");
            return ret;
        }

        if (StringUtils.isBlank(subject)) {
            subject = "no subject";
        }
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("email", mailManager);
        map.add("password", managerPassword);
        map.add("to", to);
        map.add("bcc", bcc);
        map.add("subject", subject);

        body += "<div><br><br><br></div>";
        map.add("body", body);
        String url = mailApi + "?do=sendMail";
        System.out.println(map);
        System.out.println(url);
        logger.debug(url);
        logger.debug(map);
        String responseText = restTemplate.postForObject(url, map, String.class);
        logger.debug(responseText);
        ret = parseSimpleResult(responseText);
        if (ret != null && ret.containsKey("status") && ret.get("status").equals("0")) {
            return ret;
        } else {
            throw new Exception("Send email error!");
        }
    }

    /**
     * 通过管理员帐号对外发送邮件
     *
     * @param subject
     * @param body
     */
    @Override
    public Map<String, String> sendManagerMail(String to, String subject, String body) throws Exception {
        Map<String, String> ret = new HashMap<String, String>();
        if (StringUtils.isBlank(to)) {
            ret.put("status", "-1");
            ret.put("data", "receiver cant be empty");
            return ret;
        }

        if (StringUtils.isBlank(subject)) {
            subject = "no subject";
        }
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("email", mailManager);
        map.add("password", managerPassword);
        map.add("to", to);
        map.add("subject", subject);

        body += "<div><br><br><br></div>";
        map.add("body", body);
        String url = mailApi + "?do=sendMail";
        System.out.println(map);
        System.out.println(url);
        logger.debug(url);
        logger.debug(map);
        String responseText = restTemplate.postForObject(url, map, String.class);
        logger.debug(responseText);
        ret = parseSimpleResult(responseText);
        if (ret != null && ret.containsKey("status") && ret.get("status").equals("0")) {
            return ret;
        } else {
            throw new Exception("Send email error!");
        }
    }

    private Map<String, String> parseSimpleResult(String text) {
        Document doc = null;
        Map<String, String> ret = new HashMap<String, String>();
        try {
            doc = DocumentHelper.parseText(text);
            ret = (Map<String, String>) ConvertUtils.xml2map(doc.getRootElement());
        } catch (DocumentException e) {
            // TODO Auto-generated catch block 
            logger.error(e);
            e.printStackTrace();
            return null;
        }
        return ret;

    }

    @Override
    public String randomPwd() {
        int len = 10;
        StringBuffer password = new StringBuffer();

        double rand = Math.random();
        password.append((char) (rand * ('z' - 'a') + 'a'));
        password.append((char) (rand * ('Z' - 'A') + 'A'));
        password.append((char) (rand * ('9' - '0') + '0'));

        for (int i = 3; i < len; i++) {
            double randi = Math.random();
            double randTri = Math.random() * 3;
            if (randTri >= 0 && randTri < 1) {
                password.append((char) (randi * ('9' - '0') + '0'));
            } else if (randTri >= 1 && randTri < 2) {
                password.append((char) (randi * ('Z' - 'A') + 'A'));
            } else {
                password.append((char) (randi * ('z' - 'a') + 'a'));
            }
        }
        return password.toString();
    }

    @Override
    public Map<String, String> sendManagerMailByGroup(EmailGroup json) throws Exception {

        Map<String, String> ret = new HashMap<String, String>(2);

        String[] userIds = json.getUserIds();
        String[] solicitorIds = json.getSolicitorIds();

        System.out.println(userIds.length + "\t" + solicitorIds.length);

        boolean userIsNotEmpty = true, solicitorIsNotEmpty = true;

        String userEmails = null, userNoEmails = null, solicitorEmails = null, solicitorNoEmails = null;

        /**
         * 发送邮件,其他用户均为bcc
         */
        String to = "info@ipanproprry.com";

        if (userIds == null || userIds.length == 0) {
            logger.info("user receiver is empty.");
            userIsNotEmpty = false;
        } else {
            String ids = StringUtils.join(userIds, ",");
            List<IUser> users = userService.findEamilByIds(ids);
            List<String> uE = new ArrayList<>();
            List<String> user_not_email_ids = new ArrayList<>();
            int size = users.size();
            for (int i = 0; i < size; i++) {
                IUser user = users.get(i);
                int id = user.getId();
                String email = user.getPrivateEmail();
                if (UserStatus.isEmail(email)) {
                    uE.add(email);
                } else {
                    user_not_email_ids.add(id + ":" + email);
                }
            }
            userEmails = StringUtils.join(uE, ",");
            userNoEmails = StringUtils.join(user_not_email_ids, ",");
        }

        if (solicitorIds == null || solicitorIds.length == 0) {
            logger.info("solicitor receiver is empty.");
            solicitorIsNotEmpty = false;
        } else {
            String ids = StringUtils.join(solicitorIds, ",");
            List<ISolicitor> iSolicitors = solicitorService.findEamilByIds(ids);
            int size = iSolicitors.size();

            List<String> uIso = new ArrayList<>();

            List<String> solicitor_not_email_ids = new ArrayList<>();

            for (int i = 0; i < size; i++) {
                ISolicitor iSolicitor = iSolicitors.get(i);
                int id = iSolicitor.getId();
                String email = iSolicitor.getEmail();
                if (UserStatus.isEmail(email)) {
                    uIso.add(email);
                } else {
                    solicitor_not_email_ids.add(id + ":" + email);
                }
            }
            solicitorEmails = StringUtils.join(uIso, ",");
            solicitorNoEmails = StringUtils.join(solicitor_not_email_ids, ",");
        }

        boolean notFindEmails = (!userIsNotEmpty && !solicitorIsNotEmpty) ||
                (StringUtils.isBlank(userEmails) && StringUtils.isBlank(solicitorEmails));

        if (notFindEmails) {
            ret.put("status", "-1");
            ret.put("data", "receiver cant find email");
            return ret;
        }

        String subject = json.getTitle();
        if (StringUtils.isBlank(json.getTitle())) {
            subject = "no subject";
        }

        String bccs = null;

        if (StringUtils.isNotBlank(userEmails)) {
            bccs = userEmails;
            if (StringUtils.isNotBlank(solicitorEmails)) {
                bccs += "," + solicitorEmails;
            }
        } else {
            if (StringUtils.isNotBlank(solicitorEmails)) {
                bccs = solicitorEmails;
            }
        }
        logger.info("bcc Eamils:{}", bccs);
        String url = mailApi + "?do=sendMail";
        String body = json.getContent();
        String attids = json.getAttachment();
        if (StringUtils.isNotBlank(attids)) {
            String idss = "'" + StringUtils.join(attids.split(","), "','") + "'";
            List<IAttachment> attachmentList = commonService.findAttachmentByIds(idss);
            int num = attachmentList.size();
            if (num > 0) {
                /**
                 * 超时时间
                 */
                int TIME_OUT = 10 * 10000000;
                /**
                 * 设置编码
                 */
                String CHARSET = "utf-8";
                //边界标识 随机生成 
                String BOUNDARY = UUID.randomUUID().toString();
                String PREFIX = "--", LINE_END = "\r\n";
                //内容类型
                String CONTENT_TYPE = "multipart/form-data";
                String CONTENT_POSI = "Content-Disposition: form-data; name=";

                try {
                    URL send_url = new URL(url);
                    HttpURLConnection conn = (HttpURLConnection) send_url.openConnection();
                    conn.setReadTimeout(TIME_OUT);
                    conn.setConnectTimeout(TIME_OUT);
                    conn.setDoInput(true);
                    conn.setDoOutput(true);
                    conn.setUseCaches(false);
                    conn.setRequestMethod("POST");
                    conn.setRequestProperty("Charset", CHARSET);
                    conn.setRequestProperty("connection", "keep-alive");
                    conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);

                    OutputStream outputStream = conn.getOutputStream();

                    DataOutputStream dos = new DataOutputStream(outputStream);

                    // text
                    StringBuffer strBuf = new StringBuffer();

                    strBuf.append(LINE_END).append(PREFIX).append(BOUNDARY).append(LINE_END);
                    strBuf.append(CONTENT_POSI + "\"email\"" + LINE_END + LINE_END + mailManager);
                    strBuf.append(LINE_END).append(PREFIX).append(BOUNDARY).append(LINE_END);
                    strBuf.append(CONTENT_POSI + "\"password\"" + LINE_END + LINE_END + managerPassword);
                    strBuf.append(LINE_END).append(PREFIX).append(BOUNDARY).append(LINE_END);
                    strBuf.append(CONTENT_POSI + "\"to\"" + LINE_END + LINE_END + to);
                    strBuf.append(LINE_END).append(PREFIX).append(BOUNDARY).append(LINE_END);
                    strBuf.append(CONTENT_POSI + "\"bcc\"" + LINE_END + LINE_END + bccs.replaceAll(",", ";"));
                    strBuf.append(LINE_END).append(PREFIX).append(BOUNDARY).append(LINE_END);
                    strBuf.append(CONTENT_POSI + "\"subject\"" + LINE_END + LINE_END + subject);
                    strBuf.append(LINE_END).append(PREFIX).append(BOUNDARY).append(LINE_END);
                    strBuf.append(CONTENT_POSI + "\"body\"" + LINE_END + LINE_END + body);
                    strBuf.append(LINE_END).append(PREFIX).append(BOUNDARY).append(LINE_END);

                    dos.write(strBuf.toString().getBytes());

                    if (num == 1) {

                        IAttachment attachment = attachmentList.get(0);

                        File file = new File(attachment.getRealPath());
                        StringBuffer sb = new StringBuffer();
                        sb.append(PREFIX);
                        sb.append(BOUNDARY);
                        sb.append(LINE_END);
                        sb.append(CONTENT_POSI + "\"attachment\"; filename=\"" + file.getName() + "\"" + LINE_END);
                        sb.append("Content-Type: application/octet-stream; charset=\"" + CHARSET + "\"" + LINE_END);
                        sb.append(LINE_END);
                        dos.write(sb.toString().getBytes());
                        InputStream is = new FileInputStream(file);
                        byte[] bytes = new byte[1024];
                        int len = 0;
                        while ((len = is.read(bytes)) != -1) {
                            dos.write(bytes, 0, len);
                        }
                        dos.write(LINE_END.getBytes());
                        is.close();
                    } else {
                        int i = 0;

                        for (IAttachment attachment : attachmentList) {

                            File file = new File(attachment.getRealPath());
                            StringBuffer sb = new StringBuffer();
                            sb.append(PREFIX);
                            sb.append(BOUNDARY);
                            sb.append(LINE_END);
                            sb.append(CONTENT_POSI + "\"attachment[" + i + "]\"; filename=\"" + file.getName() + "\"" + LINE_END);
                            sb.append("Content-Type: application/octet-stream; charset=\"" + CHARSET + "\"" + LINE_END);
                            sb.append(LINE_END);
                            dos.write(sb.toString().getBytes());
                            InputStream is = new FileInputStream(file);
                            byte[] bytes = new byte[1024];
                            int len = 0;
                            while ((len = is.read(bytes)) != -1) {
                                dos.write(bytes, 0, len);
                            }
                            dos.write(LINE_END.getBytes());
                            is.close();
                            i++;
                        }
                    }

                    byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINE_END).getBytes();
                    dos.write(end_data);
                    dos.flush();

                    // 读取返回数据
                    StringBuffer mes = new StringBuffer();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                    String line = null;
                    while ((line = reader.readLine()) != null) {
                        mes.append(line).append("\n");
                    }
                    System.out.println(mes.toString());
                    reader.close();
                    ret = parseSimpleResult(mes.toString());
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                    throw new Exception("attachement MalformedURLException error!");
                } catch (IOException e) {
                    e.printStackTrace();
                    throw new Exception("attachement IOException error!");
                }
            } else {
                throw new Exception("attachement with id " + attids + " not found,please check parameter.");
            }
        } else {
            MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
            map.add("email", mailManager);
            map.add("password", managerPassword);
            map.add("to", to);
            map.add("bcc", bccs.replaceAll(",", ";"));
            map.add("subject", subject);
            map.add("body", body);
            logger.debug(url);
            logger.debug(map);
            String responseText = restTemplate.postForObject(url, map, String.class);
            logger.debug(responseText);
            ret = parseSimpleResult(responseText);
        }
        if (StringUtils.isNotBlank(userNoEmails)) {
            ret.put("userWithNoEmail", userNoEmails);
        }
        if (StringUtils.isNotBlank(solicitorNoEmails)) {
            ret.put("solicitorWithNoEmail", solicitorNoEmails);
        }
        if (ret != null && ret.containsKey("status") && ret.get("status").equals("0")) {
            return ret;
        } else {
            throw new Exception("Send email error!");
        }
    }
}
